// This code contains NVIDIA Confidential Information and is disclosed to you
// under a form of NVIDIA software license agreement provided separately to you.
//
// Notice
// NVIDIA Corporation and its licensors retain all intellectual property and
// proprietary rights in and to this software and related documentation and
// any modifications thereto. Any use, reproduction, disclosure, or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA Corporation is strictly prohibited.
//
// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
//
// Information and code furnished is believed to be accurate and reliable.
// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
// information or for any infringement of patents or other rights of third parties that may
// result from its use. No license is granted by implication or otherwise under any patent
// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
// This code supersedes and replaces all information previously supplied.
// NVIDIA Corporation products are not authorized for use as critical
// components in life support devices or systems without express written approval of
// NVIDIA Corporation.
//
// Copyright (c) 2016-2020 NVIDIA Corporation. All rights reserved.


#ifndef NVBLASTTKEVENT_H
#define NVBLASTTKEVENT_H

#include <vector>

#include "NvBlastTypes.h"


namespace Nv
{
namespace Blast
{

// Forward declarations
class TkObject;
class TkActor;
class TkFamily;
class TkJoint;


/**
By the time events are dispatched, a specific TkActor may have been split and became invalid.
This structure caches the state before invalidation happened.
*/
struct TkActorData
{
	TkFamily*	family;		//!< TkFamily of the originating TkActor
	void*		userData;	//!< TkActor.userData of the originating TkActor
	uint32_t	index;		//!< TkActor::getIndex() of the originating TkActor
};


/**
Event data dispatched to TkEventListener objects.  The user may implement the abstract TkEventListener interface
and pass the listener object to a BlastTk object which dispatches events.  (See for example TkFamily.)
*/
struct TkEvent
{
	// Enums
	enum Type
	{
		Split,				//!< Sent when a TkActor is split.  See TkSplitEvent.
		FractureCommand,	//!< Sent when a TkActor generated fracture commands using TkActor::generateFracture.
		FractureEvent,		//!< Sent when a TkActor is fractured using TkActor::applyFracture.
		JointUpdate,		//!< Sent when TkJoints change their attachment state.  See TkJointUpdateEvent.

		TypeCount
	};

	// Data
	const void*	payload;	//!< Type-dependent payload data
	Type		type;		//!< See the Type enum, above

	/**
	Casts the payload data into its type-dependent format.

	\return the payload for an event of type T
	*/
	template<typename T>
	const T* getPayload() const { return reinterpret_cast<const T*>(payload); }
};


/**
Payload for TkEvent::Split events

When this event is sent, the parent TkActor that was split is no longer valid.  Therefore it is not referenced
directly in the event data.  Instead, its TkFamily, index within the TkFamily, and userData are stored.  In addition,
this event gives the child TkActors generated by the split.
*/
struct TkSplitEvent
{
	enum { EVENT_TYPE = TkEvent::Split };

	TkActorData	parentData;		//!< The data of parent TkActor that was split
	uint32_t	numChildren;	//!< The number of children into which the parent TkActor was split
	TkActor**	children;		//!< An array of pointers to the children into which the TkActor was split
};


/**
Payload for the TkEvent::FractureCommand events

Fracture Commands used to apply fracture to a TkActor.
*/
struct TkFractureCommands
{
	enum { EVENT_TYPE = TkEvent::FractureCommand };

	TkActorData				tkActorData;	//!< The data of TkActor that received the fracture command
	NvBlastFractureBuffers	buffers;		//!< The fracture commands used to modify the TkActor
};


/**
Payload for the TkEvent::FractureEvent events

Fracture Events resulting from applying fracture to a TkActor.
*/
struct TkFractureEvents
{
	enum { EVENT_TYPE = TkEvent::FractureEvent };

	TkActorData				tkActorData;	//!< The data of TkActor that received the fracture command
	NvBlastFractureBuffers	buffers;		//!< The fracture result of the modified TkActor
	uint32_t				bondsDamaged;	//!< number of damaged bonds (health remains)
	uint32_t				bondsBroken;	//!< number of broken bonds (health exhausted)
	uint32_t				chunksDamaged;	//!< number of damaged chunks (health remains) including child chunks
	uint32_t				chunksBroken;	//!< number of broken chunks (health exhausted) including child chunks
};


/**
Payload for the TkEvent::JointUpdate events

Event type sent when a TkJoint's TkActor references change.  This may indicate a joint becoming external,
simply changing actors when split events occur on one or both of the actors, or when one or both of the actors
are destroyed.
*/
struct TkJointUpdateEvent
{
	enum { EVENT_TYPE = TkEvent::JointUpdate };

	enum Subtype
	{
		External,		//!< A joint that used to be internal to a single TkActor now joins two different TkActors
		Changed,		//!< One or both of the joint's attached TkActors has changed.  The previous TkActors were distinct, however, differentiating this from the JointExternal case
		Unreferenced	//!< The joint's actors have been set to NULL.  The joint will not be used again, and the user may release the TkJoint at this time
	};

	TkJoint*	joint;		//!< The joint being updated
	Subtype		subtype;	//!< The type of update event this is (see Subtype)
};


/**
Interface for a listener of TkEvent data.  The user must implement this interface and pass it
to the object which will dispatch the events.
*/
class TkEventListener
{
public:
	/**
	Interface to be implemented by the user.  Events will be sent by BlastTk through a call to this function.

	\param[in]	events		The array of events being dispatched.
	\param[in]	eventCount	The number of events in the array.
	*/
	virtual void	receive(const TkEvent* events, uint32_t eventCount) = 0;
};

} // namespace Blast
} // namespace Nv


#endif // ifndef NVBLASTTKEVENT_H
